/*
    文件内容: Connection类,处理TcpServer中绑定和listen的相关操作
    文件名: Connection.cpp
    作者: 中国好青年(码农论坛)
    时间: 2024/9/8
*/
#include "Connection.h"

/* 
    函数名: Connection(EventLoop* loop, std::unique_ptr<Socket> clientsock)
    返回值: 无
    参  数: EventLoop* loop, epoll根; std::unique_ptr<Socket> clientsock,客户端socket地址
    函数作用: 封装处理客户端通过accept连接上来的业务
*/
Connection::Connection(EventLoop* loop, std::unique_ptr<Socket> clientsock)
                      :loop_(loop), clientchan_(new Channel(loop_, clientsock_ -> fd())), clientsock_(std::move(clientsock)),disconnectFlag_(false)
{
    //添加epoll到句柄中
    clientchan_ -> setReadCallback(std::bind(&Connection::onMessage, this));
    clientchan_ -> setCloseCallback(std::bind(&Connection::closeCallback, this));
    clientchan_ -> setErrorCallback(std::bind(&Connection::errorCallback, this));
    clientchan_ -> setWriteCallback(std::bind(&Connection::wirteCallback, this));
    clientchan_ -> enableReadEvent();
    clientchan_ -> enableEt();   
}

/* 
    函数名: ~Connection()
    返回值: 无
    参  数: 无
    函数作用: 析构函数, 释放clientsock_,connectionchan_;
*/
Connection::~Connection()
{   
    debug("~connecion %d\n",syscall(SYS_gettid));
}

/* 
    函数名: ip()
    返回值: 返回ip地址
    参  数: 无
    函数作用: 返回ip地址
*/
std::string Connection::ip()const
{
    return clientsock_ -> ip();
}

/* 
    函数名: port()
    返回值: 返回端口号
    参  数: 无
    函数作用: 返回端口号
*/
uint16_t Connection::port()const
{
    return clientsock_ -> port();
}

/* 
    函数名: fd()
    返回值: 返回文件描述符fd_
    参  数: 无
    函数作用: 返回文件描述符
*/
int Connection::fd()const
{
    return clientsock_ -> fd();
}

/* 
    函数名: closeCallback()
    返回值: 无
    参  数: 无
    函数作用: closeCallback回调函数，Channel函数调用，在创建Channel对象绑定
*/
void Connection::closeCallback()
{   
    disconnectFlag_ = true;
    clientchan_ -> remove();
    if(closeconncallback_)
       closeconncallback_(shared_from_this());
}

/* 
    函数名: errorCallback()
    返回值: 无
    参  数: 无
    函数作用: errorCallback回调函数，Channel函数调用，在创建Channel对象绑定
*/
void Connection::errorCallback()
{   
    disconnectFlag_ = true;
    clientchan_ -> remove();
    if(errorconncallback_)
        errorconncallback_(shared_from_this());
}

/* 
    函数名: setcloseconncallback(std::function<void(spConnection)> closeconncallback)
    返回值: 无
    参  数: std::function<void(spConnection)> closeconncallback,在TcpServer中传进来
    函数作用: 赋值 closeconncallback_ = closeconncallback;在本身errorCallback调用
*/
void Connection::setcloseconncallback(std::function<void(spConnection)> closeconncallback)
{
    closeconncallback_ = closeconncallback;
}

/* 
    函数名: seterrorconncallback(std::function<void(spConnection)> errorconncallback)
    返回值: 无
    参  数: std::function<void(spConnection)> errorconncallback,在TcpServer中传进来
    函数作用: 赋值 errorconncallback_ = errorconncallback;在本身errorCallback调用
*/
void Connection::seterrorconncallback(std::function<void(spConnection)> errorconncallback)
{
    errorconncallback_ = errorconncallback;
}

/* 
    函数名: seterrorconncallback(std::function<void(spConnection)> errorconncallback)
    返回值: 无
    参  数: std::function<void(spConnection)> errorconncallback,在TcpServer中传进来
    函数作用: 赋值 errorconncallback_ = errorconncallback;在本身errorCallback调用
*/
void Connection::setonmessagecallback(std::function<void(spConnection, std::string& )> onmessagecallback)
{
    onmessagecallback_ = onmessagecallback;
}

/* 
    函数名: setsendCompletecallback(std::function<void(spConnection)> sendcomletecallback)
    返回值: 无
    参  数: 无
    函数作用: 设置Tcpserver中的sendCompletecallback为回调函数,在该类中调用,发送玩数据包之后调用
*/
void Connection::setsendCompletecallback(std::function<void(spConnection)> sendcomletecallback)
{
    sendcomletecallback_ = sendcomletecallback;
}

/* 
    函数名: onMessage()
    返回值: 无
    参  数: 无
    函数作用: 处理客户端发送过来的数据,从Buffer缓冲区中获取到完整信息,交给Tcpserver::onmessage处理
*/
void Connection::onMessage()
{   
    //读取数据
    char buff[1024];
    bzero(buff, sizeof(buff));
    while(true)
    {   
        bzero(&buff, sizeof(buff));
        ssize_t nread = read(fd(), buff, sizeof(buff));
        
        if(nread > 0)
        {   
            inputbuffer_.append(buff, nread);
           
        }
        else if(nread == -1 && errno == EINTR)
        {   
            //读取数据中断, 继续读取
            continue;
        }
        else if(nread == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
        {
            //全部数据读取完毕
            //读到数据
            std::string message;
            while(true)
            {
                //更新时间戳
                lasttime_ = TimeStamp::now();
                //解析数据
                if(inputbuffer_.pickMessage(message) == false) break;
                debug("%s recive message: %s\n", lasttime_.tostring().c_str(), message.c_str());
                onmessagecallback_(shared_from_this(),message);
            }
            break;
        }
        else if(nread == 0)
        {   
            //客户端退出
            closeCallback();
            break;
        }
    } 
}

/* 
    函数名: send(const char* data, size_t size)
    返回值: 无
    参  数: const char* data,发送数据的大小 size_t size  大小
    函数作用: 将要发送的数据放到Buffer发送缓冲区中
*/
void Connection::send(const char* data, size_t size)
{   
    if(disconnectFlag_ == true)
    {
        debug("client disconnect, send return;\n");
        return;
    }
    std::shared_ptr<std::string> message(new std::string(data));
    //同一个线程id处理消息
    if(loop_ -> isEqualPid())
    {
        sendOnMessage(message);
        return;
    }
    //io线程处理发送任务,work线程处理onMessage
    loop_ -> addTaskQueue(std::bind(&Connection::sendOnMessage, this, message));
}
/* 
    函数名: sendOnMessage(std::shared<std::string> message)
    返回值: 无
    参  数: const char* data,发送的数据
    函数作用: work线程处理完后，唤醒IO线程的写事件
*/
void Connection::sendOnMessage(std::shared_ptr<std::string> message)
{
    outputbuffer_.appendWithSep(message -> data(), message -> size());
    clientchan_ -> enableWriteEvent();
}
/* 
    函数名: wirteCallback()
    返回值: 无
    参  数: 无
    函数作用: 回调函数,给新的Channel做回调,在Channel中会处理写事件,在写事件中调用该函数
*/
void Connection::wirteCallback()
{
    int writen = ::send(fd(), outputbuffer_.data(), outputbuffer_.size(), 0);
    if(writen > 0) outputbuffer_.erase(0, writen);
    
    if(outputbuffer_.size() == 0) 
    {
        clientchan_ -> disableWriteEvent();
        sendcomletecallback_(shared_from_this());
    }
}

bool Connection::isTimeout(time_t now, int val)
{
    return (now - lasttime_.to_int()) > val;
}
